﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;

namespace RDPBlock
{
    public partial class RdpBlock : ServiceBase
    {
        public RdpBlock()
        {
            InitializeComponent();

            if (System.IO.File.Exists("whitelist.txt"))
            {
                string[] lines = System.IO.File.ReadAllLines("whitelist.txt");
                foreach (var line in lines)
                {
                    string[] im = line.Split(' ');
                    whitelist.Add(new IPEntry() { Adress = System.Net.IPAddress.Parse(im[0]), Mask = System.Net.IPAddress.Parse(im[1]) });
                }
            }
        }

        public void DebugStart()
        {
            OnStart(null);
        }

        public void DebugStop()
        {
            OnStop();
        }

        Thread th = null;
        protected override void OnStart(string[] args)
        {
            m_Continue = true;
            th = new Thread(new ThreadStart(main));
            th.Start();
        }

        protected override void OnStop()
        {
            m_Continue = false;
            th.Join(1000);
            th.Abort();

        }

        bool m_Continue = false;
        Dictionary<string, List<DateTime>> failedLogins = new Dictionary<string, List<DateTime>>();
        class IPEntry
        {
            public System.Net.IPAddress Adress {get;set;}
            public System.Net.IPAddress Mask {get;set;}
        }
        List<IPEntry> whitelist = new List<IPEntry>();

        void main()
        {
            Console.WriteLine("into main");
            try
            {
                using (EventLog el = EventLog.GetEventLogs().Where(x => x.Log == "Security").FirstOrDefault())
                {
                    el.EntryWritten += new EntryWrittenEventHandler(el_EntryWritten);

                    if (!System.IO.File.Exists("blockedips.txt"))
                    {
                        Console.WriteLine("reading entries");
                        foreach (var e in el.Entries)
                        {
                            var ee = e as EventLogEntry;
                            CheckAnalyzeEntry(ee);
                        }

                        Console.WriteLine("updating blockfile");
                        UpdateBlockedIPs();
                    }
                    el.EnableRaisingEvents = true;

                    //Wait for exit
                    while (m_Continue)
                    {
                        Thread.Sleep(1000);
                    }
                    el.EnableRaisingEvents = false;
                    el.EntryWritten -= new EntryWrittenEventHandler(el_EntryWritten);
                }
            }
            catch (Exception ee)
            {
                Console.WriteLine(ee.Message + "\r\n" + ee.StackTrace);
            }

        }

        private void UpdateBlockedIPs()
        {
            List<string> curIps = new List<string>();
            if (System.IO.File.Exists("blockedips.txt"))
            {
                curIps.AddRange(System.IO.File.ReadAllLines("blockedips.txt"));
            }

            foreach (var kvp in failedLogins)
            {
                if (kvp.Value.Count > 5 && !curIps.Contains(kvp.Key))
                {
                    var ip2 = System.Net.IPAddress.Parse(kvp.Key);
                    bool isWhiteListed = IsWhiteListed(ip2);
                    if (isWhiteListed)
                        continue;
                    curIps.Add(kvp.Key);

                    /*exec block*/
                    //netsh advfirewall firewall add rule name="rdpblock-201.254.180.15" dir=in action=block remoteip=201.254.180.15 localport=3389 protocol=tcp
                    Console.WriteLine("Blocking IP: " + kvp.Key);
                    ProcessStartInfo oProInfo = new ProcessStartInfo("netsh");
                    oProInfo.Arguments = "advfirewall firewall add rule name=\"rdpblock-" + kvp.Key + "\" dir=in action=block remoteip=" + kvp.Key;// +" localport=53389,80,443,139,135, protocol=tcp";
                    oProInfo.CreateNoWindow = true;
                    oProInfo.UseShellExecute = false;
                    oProInfo.RedirectStandardInput = true;
                    oProInfo.RedirectStandardOutput = true;
                    Process oPro = new Process();
                    oPro.StartInfo = oProInfo;
                    oPro.Start();
                }
            }

            System.IO.File.WriteAllLines("blockedips.txt", curIps.ToArray());
        }

        public bool IsWhiteListed(System.Net.IPAddress ip2)
        {
            bool isWhiteListed = false;

            foreach (var ip in whitelist)
            {
                if (ip.Adress.IsInSameSubnet(ip2, ip.Mask))
                {
                    isWhiteListed = true;
                }
            }
            return isWhiteListed;
        }

        private bool CheckAnalyzeEntry(EventLogEntry ee)
        {
            if (ee.InstanceId == 4625)
            {
                string message = ee.Message;
                if (message.Contains("%%2313") && ee.EntryType == EventLogEntryType.FailureAudit)
                {
                    //Console.WriteLine(message);
                    string[] lines = message.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                    string ipLine = lines.Where(x => x.Contains("Source Network Address")).FirstOrDefault();
                    string[] parts = ipLine.Split(':');
                    string ip = parts[1].Trim();
                    Console.WriteLine("Failed Login from IP: " + ip);
                    
                    if (!failedLogins.ContainsKey(ip))
                        failedLogins.Add(ip, new List<DateTime>());

                    failedLogins[ip].Add(ee.TimeGenerated);
                    return failedLogins[ip].Count > 5;
                }
            }
            return false;
        }

        void el_EntryWritten(object sender, EntryWrittenEventArgs e)
        {
            if (CheckAnalyzeEntry(e.Entry))
            {
                UpdateBlockedIPs();
            }
        }
    }
}
